'use strict'

var after = require('after');
var express = require('../')
  , request = require('supertest')
  , assert = require('node:assert')
  , methods = require('../lib/utils').methods;

var shouldSkipQuery = require('./support/utils').shouldSkipQuery

describe('app.router', function () {
  it('should restore req.params after leaving router', function (done) {
    var app = express();
    var router = new express.Router();

    function handler1(req, res, next) {
      res.setHeader('x-user-id', String(req.params.id));
      next()
    }

    function handler2(req, res) {
      res.send(req.params.id);
    }

    router.use(function (req, res, next) {
      res.setHeader('x-router', String(req.params.id));
      next();
    });

    app.get('/user/:id', handler1, router, handler2);

    request(app)
      .get('/user/1')
      .expect('x-router', 'undefined')
      .expect('x-user-id', '1')
      .expect(200, '1', done);
  })

  describe('methods', function () {
    methods.forEach(function (method) {
      if (method === 'connect') return;

      it('should include ' + method.toUpperCase(), function (done) {
        if (method === 'query' && shouldSkipQuery(process.versions.node)) {
          this.skip()
        }
        var app = express();

        app[method]('/foo', function (req, res) {
          res.send(method)
        });

        request(app)
        [method]('/foo')
          .expect(200, done)
      })

      it('should reject numbers for app.' + method, function () {
        var app = express();
        assert.throws(app[method].bind(app, '/', 3), /argument handler must be a function/);
      })
    });

    it('should re-route when method is altered', function (done) {
      var app = express();
      var cb = after(3, done);

      app.use(function (req, res, next) {
        if (req.method !== 'POST') return next();
        req.method = 'DELETE';
        res.setHeader('X-Method-Altered', '1');
        next();
      });

      app.delete('/', function (req, res) {
        res.end('deleted everything');
      });

      request(app)
        .get('/')
        .expect(404, cb)

      request(app)
        .delete('/')
        .expect(200, 'deleted everything', cb);

      request(app)
        .post('/')
        .expect('X-Method-Altered', '1')
        .expect(200, 'deleted everything', cb);
    });
  })

  describe('decode params', function () {
    it('should decode correct params', function (done) {
      var app = express();

      app.get('/:name', function (req, res) {
        res.send(req.params.name);
      });

      request(app)
        .get('/foo%2Fbar')
        .expect('foo/bar', done);
    })

    it('should not accept params in malformed paths', function (done) {
      var app = express();

      app.get('/:name', function (req, res) {
        res.send(req.params.name);
      });

      request(app)
        .get('/%foobar')
        .expect(400, done);
    })

    it('should not decode spaces', function (done) {
      var app = express();

      app.get('/:name', function (req, res) {
        res.send(req.params.name);
      });

      request(app)
        .get('/foo+bar')
        .expect('foo+bar', done);
    })

    it('should work with unicode', function (done) {
      var app = express();

      app.get('/:name', function (req, res) {
        res.send(req.params.name);
      });

      request(app)
        .get('/%ce%b1')
        .expect('\u03b1', done);
    })
  })

  it('should be .use()able', function (done) {
    var app = express();

    var calls = [];

    app.use(function (req, res, next) {
      calls.push('before');
      next();
    });

    app.get('/', function (req, res, next) {
      calls.push('GET /')
      next();
    });

    app.use(function (req, res, next) {
      calls.push('after');
      res.json(calls)
    });

    request(app)
      .get('/')
      .expect(200, ['before', 'GET /', 'after'], done)
  })

  describe('when given a regexp', function () {
    it('should match the pathname only', function (done) {
      var app = express();

      app.get(/^\/user\/[0-9]+$/, function (req, res) {
        res.end('user');
      });

      request(app)
        .get('/user/12?foo=bar')
        .expect('user', done);
    })

    it('should populate req.params with the captures', function (done) {
      var app = express();

      app.get(/^\/user\/([0-9]+)\/(view|edit)?$/, function (req, res) {
        var id = req.params[0]
          , op = req.params[1];
        res.end(op + 'ing user ' + id);
      });

      request(app)
        .get('/user/10/edit')
        .expect('editing user 10', done);
    })

    if (supportsRegexp('(?<foo>.*)')) {
      it('should populate req.params with named captures', function (done) {
        var app = express();
        var re = new RegExp('^/user/(?<userId>[0-9]+)/(view|edit)?$');

        app.get(re, function (req, res) {
          var id = req.params.userId
            , op = req.params[0];
          res.end(op + 'ing user ' + id);
        });

        request(app)
          .get('/user/10/edit')
          .expect('editing user 10', done);
      })
    }

    it('should ensure regexp matches path prefix', function (done) {
      var app = express()
      var p = []

      app.use(/\/api.*/, function (req, res, next) {
        p.push('a')
        next()
      })
      app.use(/api/, function (req, res, next) {
        p.push('b')
        next()
      })
      app.use(/\/test/, function (req, res, next) {
        p.push('c')
        next()
      })
      app.use(function (req, res) {
        res.end()
      })

      request(app)
        .get('/test/api/1234')
        .expect(200, function (err) {
          if (err) return done(err)
          assert.deepEqual(p, ['c'])
          done()
        })
    })
  })

  describe('case sensitivity', function () {
    it('should be disabled by default', function (done) {
      var app = express();

      app.get('/user', function (req, res) {
        res.end('tj');
      });

      request(app)
        .get('/USER')
        .expect('tj', done);
    })

    describe('when "case sensitive routing" is enabled', function () {
      it('should match identical casing', function (done) {
        var app = express();

        app.enable('case sensitive routing');

        app.get('/uSer', function (req, res) {
          res.end('tj');
        });

        request(app)
          .get('/uSer')
          .expect('tj', done);
      })

      it('should not match otherwise', function (done) {
        var app = express();

        app.enable('case sensitive routing');

        app.get('/uSer', function (req, res) {
          res.end('tj');
        });

        request(app)
          .get('/user')
          .expect(404, done);
      })
    })
  })

  describe('params', function () {
    it('should overwrite existing req.params by default', function (done) {
      var app = express();
      var router = new express.Router();

      router.get('/:action', function (req, res) {
        res.send(req.params);
      });

      app.use('/user/:user', router);

      request(app)
        .get('/user/1/get')
        .expect(200, '{"action":"get"}', done);
    })

    it('should allow merging existing req.params', function (done) {
      var app = express();
      var router = new express.Router({ mergeParams: true });

      router.get('/:action', function (req, res) {
        var keys = Object.keys(req.params).sort();
        res.send(keys.map(function (k) { return [k, req.params[k]] }));
      });

      app.use('/user/:user', router);

      request(app)
        .get('/user/tj/get')
        .expect(200, '[["action","get"],["user","tj"]]', done);
    })

    it('should use params from router', function (done) {
      var app = express();
      var router = new express.Router({ mergeParams: true });

      router.get('/:thing', function (req, res) {
        var keys = Object.keys(req.params).sort();
        res.send(keys.map(function (k) { return [k, req.params[k]] }));
      });

      app.use('/user/:thing', router);

      request(app)
        .get('/user/tj/get')
        .expect(200, '[["thing","get"]]', done);
    })

    it('should merge numeric indices req.params', function (done) {
      var app = express();
      var router = new express.Router({ mergeParams: true });

      router.get(/^\/(.*)\.(.*)/, function (req, res) {
        var keys = Object.keys(req.params).sort();
        res.send(keys.map(function (k) { return [k, req.params[k]] }));
      });

      app.use(/^\/user\/id:(\d+)/, router);

      request(app)
        .get('/user/id:10/profile.json')
        .expect(200, '[["0","10"],["1","profile"],["2","json"]]', done);
    })

    it('should merge numeric indices req.params when more in parent', function (done) {
      var app = express();
      var router = new express.Router({ mergeParams: true });

      router.get(/\/(.*)/, function (req, res) {
        var keys = Object.keys(req.params).sort();
        res.send(keys.map(function (k) { return [k, req.params[k]] }));
      });

      app.use(/^\/user\/id:(\d+)\/name:(\w+)/, router);

      request(app)
        .get('/user/id:10/name:tj/profile')
        .expect(200, '[["0","10"],["1","tj"],["2","profile"]]', done);
    })

    it('should merge numeric indices req.params when parent has same number', function (done) {
      var app = express();
      var router = new express.Router({ mergeParams: true });

      router.get(/\/name:(\w+)/, function (req, res) {
        var keys = Object.keys(req.params).sort();
        res.send(keys.map(function (k) { return [k, req.params[k]] }));
      });

      app.use(/\/user\/id:(\d+)/, router);

      request(app)
        .get('/user/id:10/name:tj')
        .expect(200, '[["0","10"],["1","tj"]]', done);
    })

    it('should ignore invalid incoming req.params', function (done) {
      var app = express();
      var router = new express.Router({ mergeParams: true });

      router.get('/:name', function (req, res) {
        var keys = Object.keys(req.params).sort();
        res.send(keys.map(function (k) { return [k, req.params[k]] }));
      });

      app.use('/user/', function (req, res, next) {
        req.params = 3; // wat?
        router(req, res, next);
      });

      request(app)
        .get('/user/tj')
        .expect(200, '[["name","tj"]]', done);
    })

    it('should restore req.params', function (done) {
      var app = express();
      var router = new express.Router({ mergeParams: true });

      router.get(/\/user:(\w+)\//, function (req, res, next) {
        next();
      });

      app.use(/\/user\/id:(\d+)/, function (req, res, next) {
        router(req, res, function (err) {
          var keys = Object.keys(req.params).sort();
          res.send(keys.map(function (k) { return [k, req.params[k]] }));
        });
      });

      request(app)
        .get('/user/id:42/user:tj/profile')
        .expect(200, '[["0","42"]]', done);
    })
  })

  describe('trailing slashes', function () {
    it('should be optional by default', function (done) {
      var app = express();

      app.get('/user', function (req, res) {
        res.end('tj');
      });

      request(app)
        .get('/user/')
        .expect('tj', done);
    })

    describe('when "strict routing" is enabled', function () {
      it('should match trailing slashes', function (done) {
        var app = express();

        app.enable('strict routing');

        app.get('/user/', function (req, res) {
          res.end('tj');
        });

        request(app)
          .get('/user/')
          .expect('tj', done);
      })

      it('should pass-though middleware', function (done) {
        var app = express();

        app.enable('strict routing');

        app.use(function (req, res, next) {
          res.setHeader('x-middleware', 'true');
          next();
        });

        app.get('/user/', function (req, res) {
          res.end('tj');
        });

        request(app)
          .get('/user/')
          .expect('x-middleware', 'true')
          .expect(200, 'tj', done);
      })

      it('should pass-though mounted middleware', function (done) {
        var app = express();

        app.enable('strict routing');

        app.use('/user/', function (req, res, next) {
          res.setHeader('x-middleware', 'true');
          next();
        });

        app.get('/user/test/', function (req, res) {
          res.end('tj');
        });

        request(app)
          .get('/user/test/')
          .expect('x-middleware', 'true')
          .expect(200, 'tj', done);
      })

      it('should match no slashes', function (done) {
        var app = express();

        app.enable('strict routing');

        app.get('/user', function (req, res) {
          res.end('tj');
        });

        request(app)
          .get('/user')
          .expect('tj', done);
      })

      it('should match middleware when omitting the trailing slash', function (done) {
        var app = express();

        app.enable('strict routing');

        app.use('/user/', function (req, res) {
          res.end('tj');
        });

        request(app)
          .get('/user')
          .expect(200, 'tj', done);
      })

      it('should match middleware', function (done) {
        var app = express();

        app.enable('strict routing');

        app.use('/user', function (req, res) {
          res.end('tj');
        });

        request(app)
          .get('/user')
          .expect(200, 'tj', done);
      })

      it('should match middleware when adding the trailing slash', function (done) {
        var app = express();

        app.enable('strict routing');

        app.use('/user', function (req, res) {
          res.end('tj');
        });

        request(app)
          .get('/user/')
          .expect(200, 'tj', done);
      })

      it('should fail when omitting the trailing slash', function (done) {
        var app = express();

        app.enable('strict routing');

        app.get('/user/', function (req, res) {
          res.end('tj');
        });

        request(app)
          .get('/user')
          .expect(404, done);
      })

      it('should fail when adding the trailing slash', function (done) {
        var app = express();

        app.enable('strict routing');

        app.get('/user', function (req, res) {
          res.end('tj');
        });

        request(app)
          .get('/user/')
          .expect(404, done);
      })
    })
  })

  it('should allow literal "."', function (done) {
    var app = express();

    app.get('/api/users/:from..:to', function (req, res) {
      var from = req.params.from
        , to = req.params.to;

      res.end('users from ' + from + ' to ' + to);
    });

    request(app)
      .get('/api/users/1..50')
      .expect('users from 1 to 50', done);
  })

  describe(':name', function () {
    it('should denote a capture group', function (done) {
      var app = express();

      app.get('/user/:user', function (req, res) {
        res.end(req.params.user);
      });

      request(app)
        .get('/user/tj')
        .expect('tj', done);
    })

    it('should match a single segment only', function (done) {
      var app = express();

      app.get('/user/:user', function (req, res) {
        res.end(req.params.user);
      });

      request(app)
        .get('/user/tj/edit')
        .expect(404, done);
    })

    it('should allow several capture groups', function (done) {
      var app = express();

      app.get('/user/:user/:op', function (req, res) {
        res.end(req.params.op + 'ing ' + req.params.user);
      });

      request(app)
        .get('/user/tj/edit')
        .expect('editing tj', done);
    })

    it('should work following a partial capture group', function (done) {
      var app = express();
      var cb = after(2, done);

      app.get('/user{s}/:user/:op', function (req, res) {
        res.end(req.params.op + 'ing ' + req.params.user + (req.url.startsWith('/users') ? ' (old)' : ''));
      });

      request(app)
        .get('/user/tj/edit')
        .expect('editing tj', cb);

      request(app)
        .get('/users/tj/edit')
        .expect('editing tj (old)', cb);
    })

    it('should work inside literal parenthesis', function (done) {
      var app = express();

      app.get('/:user\\(:op\\)', function (req, res) {
        res.end(req.params.op + 'ing ' + req.params.user);
      });

      request(app)
        .get('/tj(edit)')
        .expect('editing tj', done);
    })

    it('should work in array of paths', function (done) {
      var app = express();
      var cb = after(2, done);

      app.get(['/user/:user/poke', '/user/:user/pokes'], function (req, res) {
        res.end('poking ' + req.params.user);
      });

      request(app)
        .get('/user/tj/poke')
        .expect('poking tj', cb);

      request(app)
        .get('/user/tj/pokes')
        .expect('poking tj', cb);
    })
  })

  describe(':name?', function () {
    it('should denote an optional capture group', function (done) {
      var app = express();

      app.get('/user/:user{/:op}', function (req, res) {
        var op = req.params.op || 'view';
        res.end(op + 'ing ' + req.params.user);
      });

      request(app)
        .get('/user/tj')
        .expect('viewing tj', done);
    })

    it('should populate the capture group', function (done) {
      var app = express();

      app.get('/user/:user{/:op}', function (req, res) {
        var op = req.params.op || 'view';
        res.end(op + 'ing ' + req.params.user);
      });

      request(app)
        .get('/user/tj/edit')
        .expect('editing tj', done);
    })
  })

  describe(':name*', function () {
    it('should match one segment', function (done) {
      var app = express()

      app.get('/user/*user', function (req, res) {
        res.end(req.params.user[0])
      })

      request(app)
        .get('/user/122')
        .expect('122', done)
    })

    it('should match many segments', function (done) {
      var app = express()

      app.get('/user/*user', function (req, res) {
        res.end(req.params.user.join('/'))
      })

      request(app)
        .get('/user/1/2/3/4')
        .expect('1/2/3/4', done)
    })

    it('should match zero segments', function (done) {
      var app = express()

      app.get('/user{/*user}', function (req, res) {
        res.end(req.params.user)
      })

      request(app)
        .get('/user')
        .expect('', done)
    })
  })

  describe(':name+', function () {
    it('should match one segment', function (done) {
      var app = express()

      app.get('/user/*user', function (req, res) {
        res.end(req.params.user[0])
      })

      request(app)
        .get('/user/122')
        .expect(200, '122', done)
    })

    it('should match many segments', function (done) {
      var app = express()

      app.get('/user/*user', function (req, res) {
        res.end(req.params.user.join('/'))
      })

      request(app)
        .get('/user/1/2/3/4')
        .expect(200, '1/2/3/4', done)
    })

    it('should not match zero segments', function (done) {
      var app = express()

      app.get('/user/*user', function (req, res) {
        res.end(req.params.user)
      })

      request(app)
        .get('/user')
        .expect(404, done)
    })
  })

  describe('.:name', function () {
    it('should denote a format', function (done) {
      var app = express();
      var cb = after(2, done)

      app.get('/:name.:format', function (req, res) {
        res.end(req.params.name + ' as ' + req.params.format);
      });

      request(app)
        .get('/foo.json')
        .expect(200, 'foo as json', cb)

      request(app)
        .get('/foo')
        .expect(404, cb)
    })
  })

  describe('.:name?', function () {
    it('should denote an optional format', function (done) {
      var app = express();
      var cb = after(2, done)

      app.get('/:name{.:format}', function (req, res) {
        res.end(req.params.name + ' as ' + (req.params.format || 'html'));
      });

      request(app)
        .get('/foo')
        .expect(200, 'foo as html', cb)

      request(app)
        .get('/foo.json')
        .expect(200, 'foo as json', cb)
    })
  })

  describe('when next() is called', function () {
    it('should continue lookup', function (done) {
      var app = express()
        , calls = [];

      app.get('/foo{/:bar}', function (req, res, next) {
        calls.push('/foo/:bar?');
        next();
      });

      app.get('/bar', function () {
        assert(0);
      });

      app.get('/foo', function (req, res, next) {
        calls.push('/foo');
        next();
      });

      app.get('/foo', function (req, res) {
        calls.push('/foo 2');
        res.json(calls)
      });

      request(app)
        .get('/foo')
        .expect(200, ['/foo/:bar?', '/foo', '/foo 2'], done)
    })
  })

  describe('when next("route") is called', function () {
    it('should jump to next route', function (done) {
      var app = express()

      function fn(req, res, next) {
        res.set('X-Hit', '1')
        next('route')
      }

      app.get('/foo', fn, function (req, res) {
        res.end('failure')
      });

      app.get('/foo', function (req, res) {
        res.end('success')
      })

      request(app)
        .get('/foo')
        .expect('X-Hit', '1')
        .expect(200, 'success', done)
    })
  })

  describe('when next("router") is called', function () {
    it('should jump out of router', function (done) {
      var app = express()
      var router = express.Router()

      function fn(req, res, next) {
        res.set('X-Hit', '1')
        next('router')
      }

      router.get('/foo', fn, function (req, res) {
        res.end('failure')
      })

      router.get('/foo', function (req, res) {
        res.end('failure')
      })

      app.use(router)

      app.get('/foo', function (req, res) {
        res.end('success')
      })

      request(app)
        .get('/foo')
        .expect('X-Hit', '1')
        .expect(200, 'success', done)
    })
  })

  describe('when next(err) is called', function () {
    it('should break out of app.router', function (done) {
      var app = express()
        , calls = [];

      app.get('/foo{/:bar}', function (req, res, next) {
        calls.push('/foo/:bar?');
        next();
      });

      app.get('/bar', function () {
        assert(0);
      });

      app.get('/foo', function (req, res, next) {
        calls.push('/foo');
        next(new Error('fail'));
      });

      app.get('/foo', function () {
        assert(0);
      });

      app.use(function (err, req, res, next) {
        res.json({
          calls: calls,
          error: err.message
        })
      })

      request(app)
        .get('/foo')
        .expect(200, { calls: ['/foo/:bar?', '/foo'], error: 'fail' }, done)
    })

    it('should call handler in same route, if exists', function (done) {
      var app = express();

      function fn1(req, res, next) {
        next(new Error('boom!'));
      }

      function fn2(req, res, next) {
        res.send('foo here');
      }

      function fn3(err, req, res, next) {
        res.send('route go ' + err.message);
      }

      app.get('/foo', fn1, fn2, fn3);

      app.use(function (err, req, res, next) {
        res.end('error!');
      })

      request(app)
        .get('/foo')
        .expect('route go boom!', done)
    })
  })

  describe('promise support', function () {
    it('should pass rejected promise value', function (done) {
      var app = express()
      var router = new express.Router()

      router.use(function createError(req, res, next) {
        return Promise.reject(new Error('boom!'))
      })

      router.use(function sawError(err, req, res, next) {
        res.send('saw ' + err.name + ': ' + err.message)
      })

      app.use(router)

      request(app)
        .get('/')
        .expect(200, 'saw Error: boom!', done)
    })

    it('should pass rejected promise without value', function (done) {
      var app = express()
      var router = new express.Router()

      router.use(function createError(req, res, next) {
        return Promise.reject()
      })

      router.use(function sawError(err, req, res, next) {
        res.send('saw ' + err.name + ': ' + err.message)
      })

      app.use(router)

      request(app)
        .get('/')
        .expect(200, 'saw Error: Rejected promise', done)
    })

    it('should ignore resolved promise', function (done) {
      var app = express()
      var router = new express.Router()

      router.use(function createError(req, res, next) {
        res.send('saw GET /foo')
        return Promise.resolve('foo')
      })

      router.use(function () {
        done(new Error('Unexpected middleware invoke'))
      })

      app.use(router)

      request(app)
        .get('/foo')
        .expect(200, 'saw GET /foo', done)
    })

    describe('error handling', function () {
      it('should pass rejected promise value', function (done) {
        var app = express()
        var router = new express.Router()

        router.use(function createError(req, res, next) {
          return Promise.reject(new Error('boom!'))
        })

        router.use(function handleError(err, req, res, next) {
          return Promise.reject(new Error('caught: ' + err.message))
        })

        router.use(function sawError(err, req, res, next) {
          res.send('saw ' + err.name + ': ' + err.message)
        })

        app.use(router)

        request(app)
          .get('/')
          .expect(200, 'saw Error: caught: boom!', done)
      })

      it('should pass rejected promise without value', function (done) {
        var app = express()
        var router = new express.Router()

        router.use(function createError(req, res, next) {
          return Promise.reject()
        })

        router.use(function handleError(err, req, res, next) {
          return Promise.reject(new Error('caught: ' + err.message))
        })

        router.use(function sawError(err, req, res, next) {
          res.send('saw ' + err.name + ': ' + err.message)
        })

        app.use(router)

        request(app)
          .get('/')
          .expect(200, 'saw Error: caught: Rejected promise', done)
      })

      it('should ignore resolved promise', function (done) {
        var app = express()
        var router = new express.Router()

        router.use(function createError(req, res, next) {
          return Promise.reject(new Error('boom!'))
        })

        router.use(function handleError(err, req, res, next) {
          res.send('saw ' + err.name + ': ' + err.message)
          return Promise.resolve('foo')
        })

        router.use(function () {
          done(new Error('Unexpected middleware invoke'))
        })

        app.use(router)

        request(app)
          .get('/foo')
          .expect(200, 'saw Error: boom!', done)
      })
    })
  })

  it('should allow rewriting of the url', function (done) {
    var app = express();

    app.get('/account/edit', function (req, res, next) {
      req.user = { id: 12 }; // faux authenticated user
      req.url = '/user/' + req.user.id + '/edit';
      next();
    });

    app.get('/user/:id/edit', function (req, res) {
      res.send('editing user ' + req.params.id);
    });

    request(app)
      .get('/account/edit')
      .expect('editing user 12', done);
  })

  it('should run in order added', function (done) {
    var app = express();
    var path = [];

    app.get('/*path', function (req, res, next) {
      path.push(0);
      next();
    });

    app.get('/user/:id', function (req, res, next) {
      path.push(1);
      next();
    });

    app.use(function (req, res, next) {
      path.push(2);
      next();
    });

    app.all('/user/:id', function (req, res, next) {
      path.push(3);
      next();
    });

    app.get('/*splat', function (req, res, next) {
      path.push(4);
      next();
    });

    app.use(function (req, res, next) {
      path.push(5);
      res.end(path.join(','))
    });

    request(app)
      .get('/user/1')
      .expect(200, '0,1,2,3,4,5', done);
  })

  it('should be chainable', function () {
    var app = express();
    assert.strictEqual(app.get('/', function () { }), app)
  })

  it('should not use disposed router/middleware', function (done) {
    // more context: https://github.com/expressjs/express/issues/5743#issuecomment-2277148412

    var app = express();
    var router = new express.Router();

    router.use(function (req, res, next) {
      res.setHeader('old', 'foo');
      next();
    });

    app.use(function (req, res, next) {
      return router.handle(req, res, next);
    });

    app.get('/', function (req, res, next) {
      res.send('yee');
      next();
    });

    request(app)
      .get('/')
      .expect('old', 'foo')
      .expect(function (res) {
        if (typeof res.headers['new'] !== 'undefined') {
          throw new Error('`new` header should not be present');
        }
      })
      .expect(200, 'yee', function (err, res) {
        if (err) return done(err);

        router = new express.Router();

        router.use(function (req, res, next) {
          res.setHeader('new', 'bar');
          next();
        });

        request(app)
          .get('/')
          .expect('new', 'bar')
          .expect(function (res) {
            if (typeof res.headers['old'] !== 'undefined') {
              throw new Error('`old` header should not be present');
            }
          })
          .expect(200, 'yee', done);
      });
  })
})

function supportsRegexp(source) {
  try {
    new RegExp(source)
    return true
  } catch (e) {
    return false
  }
}
